import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Random;

public class scheduler {

	ArrayList<Process> processes; // list of prrocesss
	String type; // type of scheduling
	String[] names;
	private Random rand = new Random(System.currentTimeMillis());
	ArrayList<Process> running = new ArrayList<Process>();
	int[] priorities;
	ArrayList<Process>[] s;
	int clock = 0;
	int Proceses_runned = 0; // # of process runned
	int timer = 0;

	public scheduler(ArrayList<Process> processes, String type) {
		this.processes = processes;
		this.type = type;
	}

	public scheduler(ArrayList<Process> processes, String type, String[] n,
			int[] p) {
		this.processes = processes;
		this.type = type;
		this.names = n;
		this.priorities = p;
	}

	/*
	 * gets all the running process at this clock time , ie) process which have
	 * just arrived + old ones which didnt finish yet
	 */

	public ArrayList<Process> AddtoRunningList(ArrayList<Process> processes,
			int clock) {

		ArrayList<Process> processRunningByClock = new ArrayList<Process>();
		for (int i = 0; i < processes.size(); i++) {

			if (processes.get(i).getArrivaltime() == clock) {

				processRunningByClock.add(processes.get(i));
			}

		}
		for (int i = 0; i < running.size(); i++) {
			processRunningByClock.add(running.get(i));

		}
		return processRunningByClock;
	}

	/*
	 * runs a process with a specific name , and consumes quantum
	 */
	public void RunProcessByName(String ProcessToRun, int quantum) {
		// System.out.println("i am here with name & q =" + ProcessToRun);
		// number of preocess assigned to a user
		ArrayList<Process> User_Processes = new ArrayList<Process>();

		for (int i = 0; i < running.size(); i++) {

			if (running.get(i).getName().equalsIgnoreCase(ProcessToRun)) {

				User_Processes.add(running.get(i));

			}
		}
		if (User_Processes.size() > 1) {// more than 1 process to a single
			// user

			int choice = rand.nextInt(User_Processes.size());
			System.out.println("priocess to run is #" + choice);

			Process ProcessChosenRandomly = User_Processes.get(choice);

			System.out.println("process " + ProcessChosenRandomly.getName()
					+ " of user " + ProcessChosenRandomly.getUsername()
					+ " has started running at time = " + timer);

			ProcessChosenRandomly.setRuntime(ProcessChosenRandomly.getRuntime()
					- quantum);
			System.out.println("process " + ProcessChosenRandomly.getName()
					+ " of user " + ProcessChosenRandomly.getUsername()
					+ " has finished its quantum & still remainng ");
			Proceses_runned++;
			timer++;

			if (ProcessChosenRandomly.getRuntime() <= 0) {

				System.out
						.println("process "
								+ ProcessChosenRandomly.getName()
								+ " of user "
								+ ProcessChosenRandomly.getUsername()
								+ " has Finihsed  running & removed from running list ");
				// Proceses_runned++;
				running.remove(ProcessChosenRandomly);

			}

		} else {// only available once

			System.out.println("process " + User_Processes.get(0).getName()
					+ " of user " + User_Processes.get(0).getUsername()
					+ " has started running at time = " + timer);

			User_Processes.get(0).setRuntime(
					User_Processes.get(0).getRuntime() - quantum);

			System.out.println("process " + User_Processes.get(0).getName()
					+ " of user " + User_Processes.get(0).getUsername()
					+ " has finished its quantum & still remainng ");
			Proceses_runned++;
			timer++;

			if (User_Processes.get(0).getRuntime() <= 0) {

				System.out
						.println("process "
								+ User_Processes.get(0).getName()
								+ " of user "
								+ User_Processes.get(0).getUsername()
								+ " has Finihsed  running & removed from running list ");
				// Proceses_runned++;
				running.remove(User_Processes.get(0));
			}
		}
	}

	/*
	 * The lottery scheduling algorithm
	 * 
	 * @author : mohamed tarek
	 */

	public void lottery(ArrayList<Process> processes, int total) {
		int quantum = 2;
		// Proceses_runned <= total / quantum Proceses_runned <= total / quantum
		// + 2
		// Proceses_runned < (int) (total / quantum
		boolean condition = false;
		// System.out.println("%%%%%" + total % quantum);
		if (total % quantum == 0) {
			condition = Proceses_runned < (int) (total / quantum);

		} else {
			condition = Proceses_runned <= (int) (total / quantum);

		}
		while (condition) {

			timer++;

			running = AddtoRunningList(processes, clock);// process with the

			for (int i = 0; i < running.size(); i++) {

				// System.out.println(running.get(i).getName() + " & ");
			}

			// ruun time =clock

			/*
			 * adds the Current running process USERNAME (clock matches arrival
			 * time || finished running)
			 */
			// current_process = new ArrayList<String>();
			ArrayList<String> current_process = new ArrayList<String>();
			for (int i = 0; i < running.size(); i++) {
				for (int j = 0; j < running.get(i).getPriority_of_user(); j++) {
					current_process.add(running.get(i).getName());
					// System.out.println(running.get(i).getName()
					// + " is present!");

				}
				// current_users = new ArrayList<String>();
				// current_users.add(running.get(i).getUsername());

			}
			if (running.size() > 0) {
				int choice = rand.nextInt(current_process.size());
				String ProcessToRun = current_process.get(choice);
				System.out.println("process chose in LOTTERY #" + ProcessToRun);

				// RunProcessByUser(UserToRun, quantum);
				RunProcessByName(ProcessToRun, quantum);

			}
			clock++;

			if (total % quantum == 0) {
				condition = Proceses_runned < (int) (total / quantum);

			} else {
				condition = Proceses_runned <= (int) (total / quantum);

			}
		}

	}

	public void FairShare() {
		ArrayList<ArrayList<Process>> pro = new ArrayList<ArrayList<Process>>();

		for (int i = 0; i < names.length; i++) {
			ArrayList<Process> h = new ArrayList<Process>();
			pro.add(h);
		}

		for (int i = 0; i < processes.size(); i++) {
			for (int j = 0; j < names.length; j++) {
				if (processes.get(i).userName.equals(names[j]))
					pro.get(j).add(processes.get(i));
			}
		}

		Process[][] x = new Process[pro.size()][];
		for (int i = 0; i < pro.size(); i++) {
			Process[] c = new Process[pro.get(i).size()];

			for (int j = 0; j < c.length; j++) {
				Process current = pro.get(i).get(0);
				System.out.println(current.name);
				int min = pro.get(i).get(0).arrivaltime;
				for (int k = 1; k < pro.get(i).size(); k++) {
					if (pro.get(i).get(k).arrivaltime < min) {
						current = pro.get(i).get(k);
						min = pro.get(i).get(k).arrivaltime;
					} else {
						if (pro.get(i).get(k).arrivaltime == min) {
							if (pro.get(i).get(k).name.charAt(0) < current.name
									.charAt(0)) {
								current = pro.get(i).get(k);
							}
						}
					}

				}
				pro.get(i).remove(current);
				c[j] = current;

			}

			x[i] = c;
		} // sorting

		pro.clear();

		for (int i = 0; i < x.length; i++) {
			ArrayList<Process> z = new ArrayList<Process>();
			for (int j = 0; j < x[i].length; j++) {
				z.add(x[i][j]);
			}

			pro.add(z);

		}
		int time = 0;
		boolean flag = true;
		// running program

		// System.out.println(pro.get(0).get(1));

		while (flag) {

			for (int i = 0; i < pro.size(); i++) {
				int p = priorities[i]; // user CPU share by priority
				while (p > 0) {

					if (pro.get(i).size() > 0) {

						if (pro.get(i).get(0).arrivaltime <= time) {
							System.out.println("Time " + time + ", Process "
									+ pro.get(i).get(0).name + " runs.");
							pro.get(i).get(0).runTime--;
							pro.get(i).get(0).fair_share_quantum--;

							if (pro.get(i).get(0).runTime == 0) {
								pro.get(i).remove(0);

							} else {
								if (pro.get(i).get(0).fair_share_quantum == 0) {

									Process temp = pro.get(i).get(0);

									temp.fair_share_quantum = 2;
									pro.get(i).remove(0);
									pro.get(i).add(temp);

								}
							}
							time++;
							p--;

						} else {
							p = 0;
							// i++;
						}

					} else {
						p = 0;
						// i++;
					}

				}

			}

			flag = false;
			for (int i = 0; i < pro.size(); i++) {
				if (pro.get(i).size() > 0) {
					flag = true;
				}
			}

		}

	}

	public static void main(String[] args) throws NumberFormatException,
			IOException {

		// Process a = new Process("a", 0, 5, "ahmed", 4, 1);
		// Process b = new Process("b", 1, 2, "ahmed", 4, 1);
		//
		// Process c = new Process("c", 2, 2, "jay", 4, 1);
		//
		// Process d = new Process("d", 3, 2, "jay", 4, 1);
		// Process e = new Process("a", 0, 2, "ahmed", 4, 1);
		//
		// ArrayList<Process> processes = new ArrayList<Process>();
		//
		// processes.add(a);
		// processes.add(b);
		// processes.add(c);
		// processes.add(d);
		//
		// scheduler s = new scheduler(processes, "as");
		// int max = 0;
		// for (int i = 0; i < processes.size(); i++) {
		//
		// max += processes.get(i).getRuntime();
		// }
		//
		// s.lottery(processes, max);

		ArrayList<Process> pro = new ArrayList<Process>();

		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		System.out.println("Which scheduling type would you like to use?");
		System.out.println("1- FairShare");
		System.out.println("2- Lottery");
		System.out.println("3- Multilevel Feedback");
		
		int t = Integer.parseInt(br.readLine());
		
		
		System.out.println("Enter the number of Users");
		int number_of_users = Integer.parseInt(br.readLine());
		String[] names = new String[number_of_users];
		int[] priorities = new int[number_of_users];
		for (int i = 1; i < names.length + 1; i++) {
			System.out.println("Enter the name of User " + i);
			names[i - 1] = br.readLine();
			System.out.println("Enter the priority of User " + i);
			priorities[i - 1] = Integer.parseInt(br.readLine());
		}

		boolean flag = true;
		while (flag) {
			System.out.println("Would you like to add a process?" + '\n'
					+ "If yes, press Y else press N");
			String n = br.readLine();
			if (n.charAt(0) == 'N' || n.charAt(0) == 'n') {
				flag = false;
			} else {
				System.out.println("Choose the user number of the process");
				for (int i = 1; i < names.length + 1; i++) {
					System.out.println(i + "- " + names[i - 1]);
				}
				int m = Integer.parseInt(br.readLine());
				System.out.println("Enter process name");
				String nama = br.readLine();
				System.out.println("Enter arrival time");
				int at = Integer.parseInt(br.readLine());
				System.out.println("Enter run time");
				int rt = Integer.parseInt(br.readLine());
				System.out.println("Priority of the process");
				int pr = Integer.parseInt(br.readLine());
				Process x = new Process(nama, at, rt, names[m - 1],
						priorities[m - 1], pr);
				pro.add(x);
			}
		}

		scheduler s = new scheduler(pro, "Fair Share", names, priorities);
		if(t==1){
			s.FairShare();
		}
		if(t==2){
			
		}
		if(t==3){
			
		}

	}
}
